package org.nahtanoj.contacts;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import com.google.gdata.client.Query;
import com.google.gdata.client.contacts.ContactsService;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.contacts.ContactEntry;
import com.google.gdata.data.contacts.ContactFeed;
import com.google.gdata.data.contacts.ContactGroupEntry;
import com.google.gdata.data.contacts.ContactGroupFeed;
import com.google.gdata.data.contacts.GroupMembershipInfo;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;

public class ContactEditor {
	private static final Logger log = Logger.getLogger(ContactEditor.class.getName());
	private final List<Fault> faults = new ArrayList<Fault>();
	private final HashMap<String, ContactGroup> groups = new HashMap<String, ContactGroup>();
	private final ContactsService myService;

	private final HashMap<String, ContactGroupEntry> systemGroups = new HashMap<String, ContactGroupEntry>();

	public ContactEditor(String u) throws AuthenticationException, IOException {
		this.myService = new ContactsService("CustomSync");
		//		Authenticator a = new Authenticator();

		// TODO can we use oauth2
		//		myService.setOAuth2Credentials(a.getCredential());
		Properties p = new Properties();
		FileInputStream in = new FileInputStream("passwords.properties");
		p.load(in);
		in.close();

		myService.setUserCredentials(u, p.getProperty(u));
		loadGroups();
		loadContacts();
	}

	// Create a new group
	public ContactGroupEntry createGroup(String s) {
		ContactGroupEntry newGroup = new ContactGroupEntry();
		newGroup.setTitle(new PlainTextConstruct(s));

		// Ask the service to insert the new entry
		try {
			URL postUrl = new URL(
					"https://www.google.com/m8/feeds/groups/default/full");
			try {
				newGroup = this.myService.insert(postUrl, newGroup);
			} catch (IOException e) {
				log.warning("IOException:" + e.getMessage() + " " + s);
			} catch (ServiceException e) {
				log.warning("ServiceException:" + e.getMessage() + " " + s);
			}
		} catch (MalformedURLException e) {
			log.warning("MalformedURLException:" + e.getMessage() + " " + s);
		}
		return newGroup;
	}

	//	public void getContact(String hash) {
	//		for (String groupUrl : this.groups.keySet()) {
	//			for (ContactEntry ce : this.groups.get(groupUrl).getContacts()) {
	//				for (ExtendedProperty p : ce.getExtendedProperties()) {
	//					if (p.getName().equals("hash")) {
	//						if (p.getValue().equals(hash)) {
	//							System.out.println(this.groups.get(groupUrl).getGroup().getTitle().getPlainText() + " " + ce.getName().getFullName().getValue());
	//						}
	//					}
	//				}
	//			}
	//		}
	//	}

	public List<Fault> getFaults() {
		return this.faults;
	}

	public String getGroup(String group) {
		String groupUrl = null;
		for (String url : this.groups.keySet()) {
			if (this.groups.get(url).getGroup().getTitle().getPlainText().equals(group)) {
				if (groupUrl == null) {
					groupUrl = url;
				} else {
					log.warning("More than one group with the same title");
				}
			}
		}
		return groupUrl;
	}

	public HashMap<String, ContactGroup> getGroups() {
		return this.groups;
	}

	public void insertContact(ContactEntry c) throws IOException, ServiceException {
		URL url = new URL("http://www.google.com/m8/feeds/contacts/default/full");
		try {
			myService.insert(url, c);
			log.info("Inserted:" + c.getName().getFullName().getValue());
		} catch (IllegalStateException e) {
			log.severe(e.getMessage() + " " + c.getName().getFullName().getValue());
		}
	}

	private void loadContacts() {
		try {
			URL url = new URL("https://www.google.com/m8/feeds/contacts/default/full");
			Query myQuery = new Query(url);
			myQuery.setMaxResults(100000);

			try {
				ContactFeed resultFeed = myService.query(myQuery,
						ContactFeed.class);
				for (ContactEntry entry : resultFeed.getEntries()) {
					for (GroupMembershipInfo group : entry
							.getGroupMembershipInfos()) {
						if (groups.get(group.getHref()) != null) {
							groups.get(group.getHref()).addContact(entry);
						}
					}
				}
			} catch (IOException e) {
				log.warning("IOException:" + e.getMessage());
			} catch (ServiceException e) {
				log.warning("ServiceException:" + e.getMessage());
			}
		} catch (MalformedURLException e) {
			log.warning("MalformedURLException:" + e.getMessage());
		}
	}

	private void loadGroups() {
		try {
			URL url = new URL("http://www.google.com/m8/feeds/groups/default/base");
			Query myQuery = new Query(url);
			myQuery.setMaxResults(100000);
			try {
				ContactGroupFeed resultFeed = myService.query(myQuery, ContactGroupFeed.class);
				for (ContactGroupEntry groupEntry : resultFeed.getEntries()) {
					if (groupEntry.getTitle().getPlainText().startsWith("System")) {
						systemGroups.put(groupEntry.getTitle().getPlainText(), groupEntry);
					}
					this.groups.put(groupEntry.getSelfLink().getHref(), new ContactGroup(groupEntry));
				}
			} catch (IOException e) {
				log.warning("IOException:" + e.getMessage());
			} catch (ServiceException e) {
				log.warning("ServiceException:" + e.getMessage());
			}
		} catch (MalformedURLException e) {
			log.warning("MalformedURLException:" + e.getMessage());
		}
	}

	//	public void saveContacts(ContactSpreadsheet cs) {
	//		for (String s : cs.getGroups().keySet()) {
	//			for (Contact c : cs.getGroups().get(s)) {
	//				try {
	//					updateGroups(s, c);
	//				} catch (IOException e) {
	//					log.warning("IOException:" + e.getMessage());
	//				} catch (ServiceException e) {
	//					log.warning("ServiceException:" + e.getMessage());
	//				}
	//			}
	//		}
	//	}

	public void updateContact(ContactEntry c) {
		try {
			URL url = new URL(c.getEditLink().getHref());
			this.myService.update(url, c);
			log.info("Updated:" + c.getName().getFullName().getValue());
		} catch (MalformedURLException e) {
			log.warning("updateContact: MalformedURLException:" + e.getMessage());
		} catch (IOException e) {
			log.warning("updateContact: IOException:" + e.getMessage());
		} catch (ServiceException e) {
			log.warning("updateContact: ServiceException:" + e.getMessage());
		}
	}

	// Update the group with the new contact
	// If contact exists - update changes
	// Otherwise add contact
	// More than one match generates a fault entry
	//	private void updateGroup(String s, Contact c) throws IOException,
	//			ServiceException {
	//		ContactGroup g = this.groups.get(s);
	//		List<ContactEntry> matches = g.matchContact(c);
	//		if (matches.size() == 1) {
	//			// One match - update the fields
	//			ContactEntry cupdate = c.updateContact(matches.get(0), g.getGroup(), systemGroups.get("System Group: My Contacts"));
	//			URL url = new URL(cupdate.getEditLink().getHref());
	//			this.myService.update(url, cupdate);
	//		} else {
	//			if (matches.size() == 0) {
	//				URL url = new URL(
	//						"http://www.google.com/m8/feeds/contacts/default/full");
	//				myService.insert(url, c.getContact(g.getGroup(), systemGroups.get("System Group: My Contacts")));
	//			} else {
	//				// More than one match - generate a fault
	//				faults.add(new Fault("ContactEditor.updateGroup",
	//						"Multiple matches", c.getRow() + ":" + c.getFirstName()
	//								+ " " + c.getLastName()));
	//			}
	//		}
	//	}

	// Searches for the contact c in group s in the ContactGroups
	// If found - checks for changes and updates
	// Otherwise - inserts new contact
	//	private void updateGroups(String g, Contact c) throws IOException,
	//			ServiceException {
	//		if (g == null || c == null) {
	//			return;
	//		}
	//		boolean found = false;
	//		if (g.equals("Family")) {
	//			g = "System Group: Family";
	//		}
	//		if (g.equals("Friend")) {
	//			g = "System Group: Friends";
	//		}
	//		for (String s : this.groups.keySet()) {
	//			if (this.groups.get(s).getGroup().getTitle().getPlainText().equals(g)) {
	//				updateGroup(s, c);
	//				found = true;
	//			}
	//		}
	//		// Only update if not found and not a system group
	//		if (found == false) {
	//			// Group does not exist, create it and add contact
	//			this.groups.put(g, new ContactGroup(createGroup(g)));
	//			updateGroup(g, c);
	//		}
	//	}

	//	public String addGroup(String category) {
	//		ContactGroupEntry newGroup = new ContactGroupEntry();
	//		newGroup.setTitle(new PlainTextConstruct(category));
	//		URL postUrl = new URL("https://www.google.com/m8/feeds/groups/default/full");
	//		ContactGroupEntry createdGroup = this.myService.insert(postUrl, newGroup);
	//		return null;
	//	}
}
